\chapter{Deployment Issues}
\label{chap:deploy}

% make sure this says something about controlling database connection
% info
% If you want to change to a different database, you can arrange that now.
% Click on the `App Config', you'll see something like Figure
% \ref{fig:appconfig}.
% 
% \begin{figure}
% \includegraphics[width=6in]{appconfig}
% \caption{Application configuration table.}
% \label{fig:appconfig}
% \end{figure}
% 
% To change databases, simply change the dbconn config parameter, so it
% has the proper DBI dsn string for connecting to your database.  You probably
% also need to supply a dbuser.  Further, you will need to add a new
% config param called dbpass, if your database expects a password for
% your dbuser.  If so, type `dbpass' into the input box next to the
% `New Config Statement' button, then press the button, and add the password.

In the last chapter, we saw how to build an app with tentmaker and run it
with a test server (app.server).  Bigtop also made a CGI script for us, which
we could immediately deploy merely by moving it to the cgi-bin
directory.\footnote{so long as Apache can read and write the build directory
and read the build and docs directories}
Here we will look at two additional deployment issues.  First, we will
move the app into a \verb+mod_perl+ environment.  Second, we will extract the
configuration information (conf) from the app into the Gantry::Conf scheme.
The latter will allow us
to easily deploy multiple instances of our app and share the app's conf info
with external scripts.

\section{Moving to Mod Perl}

I'm not going to explain how to put a working
\verb+mod_perl+\index{mod perl@\verb+mod_perl+}
installation onto
your server.\begin{footnote}If you need advice about that, you should visit
\verb+http://perl.apache.org+.  The only other comment I will make is
a suggestion.  Pick a version of \verb+mod_perl+ in 1.3, 2.0, or
2.2 sequences.  Avoid versions numbered 1.99.\end{footnote}
But, I am going to explain how to deploy a Gantry app via
\verb+mod_perl+, once you have \verb+mod_perl+ working.
Bigtop can help with much of our work, so begin by restarting tentmaker
and giving it the \verb+addressbook.bigtop+ file from the last chapter:

{\footnotesize
\begin{verbatim}
tentmaker docs/addressbook.bigtop
\end{verbatim}
}

First -- and foremost -- on the `Bigtop Config'
tab\index{bigtop!config in tentmaker}\index{tentmaker!bigtop config},
change the engine to
the \verb+mod_perl+ version you have installed (mine was 1.3 when I wrote
this).

Now, click on the `Backends' tab.  Uncheck the box for
CGI Gantry\index{CGI!Gantry bigtop backend!turning off},
which will
stop bigtop from making app.cgi and app.server.  Then check the box for
HttpdConf Gantry\index{HttpdConf Gantry!turning on},
to start generating docs/httpd.conf\index{httpd.conf!generation}.

Since our app is not installed on the system yet, we need to tell
\verb+mod_perl+ where to find it.  A regular
\verb+use lib+\index{use lib@\verb+use_lib+}\index{httpd.conf!Perl
block statements}
statement will do,
but we need to place it carefully.  One good place to put it is at the top
of a \verb+<Perl>+ block in httpd.conf.  Here's how to make bigtop do that.

Go to the `App Body'
tab\index{bigtop!app body in tentmaker}\index{tentmaker!app body}.
Create a new block of type
`Literal'\index{literal!making in tentmaker}
(leave the
`Name:' box blank).  Scroll down to that block and select `Literal Type:'
`PerlTop\index{PerlTop literal!making in tentmaker}.'
This is the instruction telling bigtop to put a statement at the top of
the \verb+<Perl>+ block in httpd.conf.  In the `String:' box, type a complete
use lib statement (right down to the semi-colon) which will lead perl to the
lib subdirectory of the build directory.  Mine looks like this:

\begin{verbatim}
use lib '/home/pcrow/AddressBook/lib';
\end{verbatim}

You might even want to include four leading spaces, if you care about the
indentation in the generated conf file.

Now we need to deal with some file system
paths\index{mod perl@\verb+mod_perl+!paths}\index{paths!mod
perl@\verb+mod_perl+},
which were relative for app.server,
but must now be absolute.  While still in tentmaker, on the `App Body'
tab, scroll to and edit the first `Config Block.'  Add a new config
variable called \verb+root+.  Make it
an absolute path to the \verb+html/templates+ directory of the AddressBook
build directory.
This directory must be readable by the user Apache runs as.

The other path\index{paths!app.db in mod perl} that needs adjustment is for
app.db\index{app.db!mod perl path}.
For the app to work, the user Apache runs as needs to own both the app.db
file and the directory where it lives.  In addition to ownership, it
obviously needs write permissions, so it can write updates to the database.
After you decide where to locate app.db, add a fully qualified absolute path
to it in the
`dbconn\index{dbconn!mod perl@\verb+mod_perl+}\index{tentmaker!dbconn}'
value.

Alternatively, you could switch to a different database
engine\index{tentmaker!database engine change}\index{database!changing
engine in tentmaker}.
Make that
change in the same place, by altering the database connection info string.
Then, don't forget to build the database.  There should be schema files
for use with PostgreSQL and MySQL in the docs directory.

Save the file and regenerate the app:

\begin{verbatim}
bigtop docs/addressbook.bigtop all
\end{verbatim}

There is only one more thing we need to do to launch under \verb+mod_perl+.
We, need to modify the system httpd.conf for our server to tell it about our
app.
For this app, I added the following to my \verb+mod_perl+ enabled
httpd.conf\index{virtual host}\index{httpd.conf!virtual host}:

{\footnotesize
\begin{verbatim}
<VirtualHost address.devel.example.com>
    ServerName       address.devel.example.com
    DocumentRoot     /home/pcrow/AddressBook/html
    CustomLog        /home/pcrow/logs/combined.log combined
    ErrorLog         /home/pcrow/logs/addressbook.err

    Include /home/pcrow/AddressBook/docs/httpd.conf
</VirtualHost>
\end{verbatim}
}

You might need to make a DNS entry to use the above approach.  We
have a wild card which lets anything.devel... map to these virtual hosts,
so we can make them on the fly.  That entry looks like this:

{\footnotesize
\begin{verbatim}
devel.example.com     IN  A   192.168.0.1
*.devel.example.com   IN  A   192.168.0.1
\end{verbatim}
}

The first line is the regular entry for the server's default name.  The
second line has an asterisk wildcard.  Domain names and IP addresses
have been changed to protect the guilty.  With all that in place,
start or restart the web server and hit the app again at its new URL.

\section{Moving to Gantry::Conf\index{Gantry::Conf}}

This section explains how configuration information is supplied for
the application of the last chapter as it was deployed in the previous section.
One of the key goals for Gantry is flexible configuration.  That
lead to Gantry::Conf, the subject of this section.  Later subsections will
explain two key example scenarios in which this flexibility is needed:
deploying multiple instances of the same app in the same server and sharing
conf info with external scripts or other apps.

Gantry::Conf was Frank
Wiles'\index{Wiles, Frank}\index{Boss, The}
idea (he's my boss, so don't be surprised
if I gush in this section).  He was tired of being told by external
app suppliers how he should store his conf info.  He didn't want to do the
same to other people when we deliver an app.  Further, he knew that
our shop was suffering from the difficulty of conf info duplication due
to web apps relying on httpd.conf, while cron jobs and daemons did
something different.
This section explains how Gantry::Conf works by showing how bigtop set it
up for the existing AddressBook app.

We can turn again to tentmaker\index{tentmaker!moving to Gantry::Conf}
this time for a tour.  Click on `Backends\index{tentmaker!backends tab}.'
The box for Conf Gantry\index{Conf Gantry bigtop backend} is checked.
And the instance name for the app is `addressbook,' as you can see in the
box at the far right labeled `instance.'  Also note the file name
in the `conffile' box.  Let's delete that name and move to a single
master Gantry::Conf file for all our apps.  Note that the `Use
Gantry::Conf\index{Gantry::Conf!with HttpdConf Gantry bigtop backend}'
box in the far right hand column in the
HttpdConf Gantry\index{HttpdConf Gantry bigtop backend!with Gantry::Conf}
row.  This tells that backend to omit the conf information,
since we are trying to centralize it, not 
duplicate it.  Since we are still dual developing with \verb+mod_perl+ and
the CGI
Gantry\index{CGI!Gantry bigtop backend!with Gantry::Conf}
backend, bigtop did the same thing for it.

Save the file.  Regenerate with bigtop.  If you restart the server and hit
it now, you will receive an error, because Gantry::Conf does not know where
to find your config.  Copy `AddressBook.gantry.conf' from the docs
directory to the /etc/gantry.d\index{gantry.d}
directory, or make a symbolic
link\index{symbolic link!for Gantry::Conf
files}.\index{Gantry::Conf!symbolic links}
Make sure to use a wild card include\index{gantry.conf!wildcard include}
in your /etc/gantry.conf\index{gantry.conf}:

\begin{verbatim}
include /etc/gantry.d/*.conf
\end{verbatim}

If you can't create or modify
/etc/gantry.conf\index{gantry.conf!alternate name},
make a file somewhere which
the Apache User can read.  Put that file's name in the `conffile' box
in tentmaker for the Conf Gantry backend.  Save and regenerate.
Then, create the master conf file with a wild card like the one shown
above, but pick a directory you can write to and the Apache User can read
from.

Now it is safe to restart the app and point the browser to it.

\subsection{Multiple instances\index{multiple app instances}}

One of the key uses of Gantry::Conf is in easing deployment of multiple
instances of the same app.  For instance, if my wife and I each want a
separate address book, we can deploy two instances of the app.  Both will
share some things, like the site appearance and even the database user and
password.  But, they will store data in different databases.  This section
explains how to accomplish this.

First, there is no difficulty in setting up a second virtual server using
the same code.  Just duplicate the
VirtualHost\index{virtual host}
shown above and change the
names until it looks more like this:

{\footnotesize
\begin{verbatim}
<VirtualHost philaddress.devel.example.com>
    ServerName       philaddress.devel.example.com
    DocumentRoot     /home/pcrow/AddressBook/html
    CustomLog        /home/pcrow/logs/combined.log combined
    ErrorLog         /home/pcrow/logs/addressbook.err

    Include /home/pcrow/AddressBook/docs/phil.conf
</VirtualHost>
\end{verbatim}
}

Bigtop generated the included \verb+httpd.conf+.  The original
looks like this:

{\footnotesize
\begin{verbatim}
<Perl>
    #!/usr/bin/perl

    use Apps::AddressBook qw{ -Engine=MP13 -TemplateEngine=TT };
    use Apps::AddressBook::Address;
    use Apps::AddressBook::Birth;
</Perl>

<Location /apps>
    PerlSetVar GantryConfInstance address
</Location>

<Location /apps/address>
    SetHandler  perl-script
    PerlHandler Apps::AddressBook::Address
</Location>

<Location /apps/birthday>
    SetHandler  perl-script
    PerlHandler Apps::AddressBook::Birth
</Location>
\end{verbatim}
}

Notice that I'm letting Lisa keep the original URL, in case she set
a bookmark to it.  Also note that I referred to
phil.conf\index{phil.conf, for address book} in the new host.
I'll have to
copy her conf and update it, but only by changing the
GantryConfInstance\index{Gantry::Conf!setting instance in mod perl}:

{\footnotesize
\begin{verbatim}
PerlSetVar GantryConfInstance philaddress
\end{verbatim}
}

This is slightly painful, since I have to remember to repeat this copy and
change process each time the httpd.conf changes.  (I have a back burner
TODO item to address this.)

With the web server conf updated, I need to correct the conf.  The easiest
way to do that is to again copy the conf, but I want a more robust solution.
I'm going to move the shared conf values into /etc/gantry.conf.  Everything
is shared in this case except the dbconn value, so it will be the lone entry
in each instance's conf file.  Here are the files, starting with
/etc/gantry.conf\index{gantry.conf}:

{\footnotesize
\begin{verbatim}
<shared address_shared>
    dbuser apache
    template_wrapper genwrapper.tt
    root /home/pcrow/AddressBook/html
</shared>
<instance address>
    ConfigureVia FlatFile Config::General \
            /home/pcrow/AddressBook/docs/AddressBook.conf
    use address_shared
</instance>
<instance philaddress>
    use address_shared
    dbconn dbi:Pg:dbname=philcontact
</instance>
\end{verbatim}
}

Lisa's instance now wants an individual conf file which has one line:

{\footnotesize
\begin{verbatim}
dbconn dbi:Pg:dbname=contact
\end{verbatim}
}

Now when I restart the server, users hitting
{\footnotesize
\begin{verbatim}
http://addressbook.devel.example.com/contacts
\end{verbatim}
}
\noindent
will access Lisa's data.  Users hitting the following URL will access
my data:
{\footnotesize
\begin{verbatim}
http://philaddress.devel.example.com/contacts
\end{verbatim}
}

There are many other ways to configure the app to work with two instances
using Gantry::Conf.  As with Perl, there is more than one way to do it.
Picking one you like takes a bit of experience.  I've shown a couple of
approaches here to get you started.  Note that all of these have abandoned
conf generation for a manual approach.  One day it may be possible to
generate instance specific conf, but that day has not yet dawned.

\subsection{Sharing conf with
batch\index{batch jobs}\index{cron!jobs, conf} processes}

Half of the reason for developing Gantry::Conf was to ease the sharing of
conf between the web delivered pieces of an app and its batch processes.
Suppose we want the AddressBook app to spam us with upcoming birthdays.
We can now write a little cron script to accomplish that and configure it via
the same conf that the app uses.

To show how this works, suppose that I want an email reminder on a periodic
basis (say once a week) of all the birthdays near the the current date.
This would enable me to send cards, if I weren't so mean spirited.
Here is the
program\index{program!birth day reminder}\index{script!birth day
reminder}\index{birth day reminder}
which does the job for me:

% /home/pcrow/play/AddressBook/scripts/reminder
% lines numbered with srcgantry/docs/book/staging/number_lines
{\footnotesize
\begin{verbatim}
 1 #!/usr/bin/perl
 2 use strict;
 3 use warnings;
 4 
 5 use lib '/home/pcrow/AddressBook/lib';
 6 
 7 use Date::Manip qw( ParseDate DateCalc UnixDate );
 8 use Gantry::Conf;
 9 use AddressBook::Model;
10 use AddressBook::Model::bday qw( $BDAY );
11 
12 my $instance = shift || 'address';
13 
14 my $conf = Gantry::Conf->retrieve( { instance => $instance } );
15 
16 my $schema = AddressBook::Model->connect(
17     $conf->{ dbconn }, $conf->{ dbuser }, $conf->{ dbpass },
18 );
19 
20 my $today = ParseDate( 'today' );
21 my $comp_err;
22 
23 my @bdays = $BDAY->ssearch( $schema );
24 
25 foreach my $bday_row ( @bdays ) {
26     ( my $db_date = $bday_row->bday ) =~ s{-}{/}g;
27     my $bday    = ParseDate( $db_date );
28     my $name    = $bday_row->name;
29     my $family  = $bday_row->address->foreign_display();
30 
31     my $separation = DateCalc( $today, $bday, \$comp_err );
32     my ( $weeks, $days ) = ( split /:/, $separation )[2,3];
33     my $sign = substr $separation, 0, 1;
34 
35     my $prep = ( $sign eq '+' ) ? 'from now' : 'ago';
36 
37     $days += 7 * $weeks;
38 
39     my $short_bdate = UnixDate( $bday, "%B %e" );
40 
41     if ( abs( $days ) < 14 ) {
42         print "$name belonging to $family birth day:\n"
43               .   "   $days days $prep on $short_bdate.\n";
44     }
45 }
\end{verbatim}
}

The program begins on lines 1-3 like any other, with a shebang line and
a request for strictures and warnings.  Then it uses the
same lib path (line 5) as the web server, so they will share the code modules.
I wouldn't need the use lib statement, if I had used \verb+./Build install+
to actually install the application.

From Date::Manip\index{Date::Manip} (line 7)
I used ParseDate\index{ParseDate}
to turn strings into dates, DateCalc\index{DateCalc} to compare dates,
and UnixDate for pretty output.  There are many other ways to handle the
dates.  This one came to my mind first, but has no other merit.
For instance, I could have let the database do
the date work, but chose to do it in Perl in a -- probably vain -- attempt
to be database agnostic.  Other people might have chosen other date
modules, even if they conceded that the work should be done in Perl.

The rest of the uses (lines 8-10) bring in \verb+Gantry::Conf+, the base
model, and the \verb+bday+ table model (and its abbreviation \verb+$BDAY+).

The user supplies the conf instance name (shifted in on line 12) at the command
line\index{Gantry::Conf!command line conf
instance}\index{command line!conf instance},
so Lisa
and I can each receive separate birthday updates.  That instance is
passed to Gantry::Conf's retrieve method (line 14), which returns the
proper hash of conf info.

To connect to the database, I use the base model (lines 16-18), which
inherits from \verb+DBIx::Class::Schema+.

After storing today's date in a Date::Manip string (line 20), I ask the
\verb+bday+
table model, through its all caps alias, to return all of its rows, using
some excessive Gantry
sugar (line 23).  Since I have an actual schema object in hand, I can
use \verb+ssearch+ instead of typing:

{\footnotesize
\begin{verbatim}
$schema->resultset( $class->table_name )->search( undef );
\end{verbatim}
}
\noindent
When you have a Gantry site object, it is easier to use \verb+gsearch+
instead, passing it the gantry site object as its first argument.

Looping through each birthday row (lines 25-45), I pull out the data I
want to use.  Note that I can call
\verb+foreign_display+\index{foreign display@\verb+foreign_display+}
on the \verb+address+ attribute
of each birth day row (line 29), to get the family name from the address table.
This is part of why we always want a \verb+foreign_display+ for each table.

The rest is just a bit of Date::Manip work and pretty printing.
I'll leave the actual scheduling of the job up to you.  If I really installed
this, I would use cron\index{cron}.  Note that the email is indirect.
The cronned
program prints to standard out, which cron will send to my mail on the local
system.  That's enough for me.  Feel free to add a genuine email feature.

\section*{Summary}

Gantry::Conf is even more flexible than what I've shown here.  Unfortunately,
it is beyond the scope of this book to show more of its details.  For instance,
If I had more room, I could show how to set up a secure conf server which apps
on multiple boxes could contact via https to retrieve shared conf.  Further,
we could explore how to write your own provider, so you could replace flat
file conf with LDAP or some other clever scheme.  Alas, we'll have to turn
away from the fascinating subject of configuration and return to the world
of web apps.  For more information on Gantry::Conf see the perldoc for
Gantry::Conf::FAQ, Gantry::Conf::Tutorial, and the other modules in the
Gantry::Conf namespace.
